package com.flowable.controller;

import org.flowable.engine.HistoryService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/leave/boss/statistics")
public class BossApprovalStatisticsController {

    @Autowired
    private HistoryService historyService;

    /**
     * 获取老板审批的统计数据
     * - 本周老板已批准数量
     * - 本周老板已拒绝数量
     * - 本月老板审批的平均请假天数
     */
    @GetMapping
    public Map<String, Object> getBossApprovalStatistics() {
        Map<String, Object> result = new HashMap<>();

        // 1. 计算本周老板已批准和已拒绝的数量
        Date weekStart = getStartOfWeek();
        Date weekEnd = getEndOfWeek();
        
        long approvedCount = countBossApprovedInstances(weekStart, weekEnd, "approved");
        long rejectedCount = countBossApprovedInstances(weekStart, weekEnd, "rejected");
        
        // 2. 计算本月老板审批的平均请假天数
        Date monthStart = getStartOfMonth();
        Date monthEnd = getEndOfMonth();
        
        double avgDays = calculateBossApprovedAverageDays(monthStart, monthEnd);
        
        // 3. 封装结果
        result.put("approvedCount", approvedCount);
        result.put("rejectedCount", rejectedCount);
        result.put("avgDays", Math.round(avgDays * 10) / 10.0); // 保留一位小数

        System.err.println(result);
        return result;
    }

    /**
     * 统计指定时间范围内老板审批的流程数量（按审批结果）
     */
    private long countBossApprovedInstances(Date startTime, Date endTime, String outcome) {
        // 1. 先查询老板审批节点（bossApproval）处理过的任务对应的流程实例ID
        List<String> bossApprovedProcessIds = historyService.createHistoricTaskInstanceQuery()
                .taskDefinitionKey("bossApproval") // 老板审批节点ID（需与BPMN一致）
                .taskCandidateGroup("boss") // 老板角色组（或用.taskAssignee("bossUserId")指定具体用户）
                .taskCompletedAfter(startTime)
                .taskCompletedBefore(endTime)
                .finished() // 已完成的审批任务
                .list()
                .stream()
                .map(historicTask -> historicTask.getProcessInstanceId()) // 提取流程实例ID
                .distinct() // 去重（一个流程可能经过老板多次审批）
                .collect(Collectors.toList());

        List<HistoricTaskInstance> managerTasks = historyService.createHistoricTaskInstanceQuery()
                .taskDefinitionKey("bossApproval") // 领导审批节点ID（需与BPMN文件一致）
                .taskCandidateGroup("boss") // 审批组（与BPMN一致）
                .taskCompletedAfter(startTime)
                .taskCompletedBefore(endTime)
                .finished() // 已完成的任务
                .list();

        long approvedCount = managerTasks.stream()
                .map(HistoricTaskInstance::getProcessInstanceId) // 获取流程实例ID
                .distinct() // 去重（一个流程可能有多个任务，但只统计一次）
                .filter(processInstanceId -> {
                    // 查询流程实例级变量"approvalResult"
                    HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery()
                            .processInstanceId(processInstanceId)
                            .singleResult();
                    if (processInstance == null) {
                        return false;
                    }
                    // 获取流程实例变量（注意：变量需存在，否则返回null）
                    HistoricVariableInstance approvalResult = historyService.createHistoricVariableInstanceQuery()
                            .processInstanceId(processInstanceId)
                            .variableName("approvalResult")
                            .singleResult();


                    // 2. 处理变量不存在的情况
                    if (approvalResult == null) {
                        return false;
                    }
                    Object value = approvalResult.getValue();
                    return value != null && "approved".equals(value.toString());
                })
                .count();

        if (bossApprovedProcessIds.isEmpty()) {
            return 0;
        }

        // 2. 筛选这些流程中审批结果符合条件的数量
        return approvedCount;
    }

    /**
     * 计算本月老板审批的请假流程的平均天数
     */
    private double calculateBossApprovedAverageDays(Date startTime, Date endTime) {
        // 1. 获取老板本月审批过的流程实例ID
        List<String> bossApprovedProcessIds = historyService.createHistoricTaskInstanceQuery()
                .taskDefinitionKey("bossApproval")
                .taskCandidateGroup("boss")
                .taskCompletedAfter(startTime)
                .taskCompletedBefore(endTime)
                .finished()
                .list()
                .stream()
                .map(historicTask -> historicTask.getProcessInstanceId())
                .distinct()
                .collect(Collectors.toList());

        if (bossApprovedProcessIds.isEmpty()) {
            return 0.0;
        }

        // 2. 计算这些流程的平均请假天数
        List<Double> leaveDaysList = bossApprovedProcessIds.stream()
                .map(processId -> {
                    HistoricVariableInstance daysVar = historyService.createHistoricVariableInstanceQuery()
                            .processInstanceId(processId)
                            .variableName("days") // 请假天数变量名
                            .singleResult();
                    
                    if (daysVar != null && daysVar.getValue() instanceof Number) {
                        return ((Number) daysVar.getValue()).doubleValue();
                    }
                    return 0.0;
                })
                .collect(Collectors.toList());

        return leaveDaysList.stream()
                .mapToDouble(Double::doubleValue)
                .average()
                .orElse(0.0);
    }

    // 日期工具方法（与之前相同）
    private Date getStartOfWeek() {
        LocalDate today = LocalDate.now();
        LocalDate weekStart = today.minusDays(today.getDayOfWeek().getValue() - 1);
        return Date.from(weekStart.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    private Date getEndOfWeek() {
        LocalDate today = LocalDate.now();
        LocalDate weekEnd = today.plusDays(7 - today.getDayOfWeek().getValue());
        return Date.from(weekEnd.atTime(23, 59, 59).atZone(ZoneId.systemDefault()).toInstant());
    }

    private Date getStartOfMonth() {
        LocalDate today = LocalDate.now();
        LocalDate monthStart = today.withDayOfMonth(1);
        return Date.from(monthStart.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    private Date getEndOfMonth() {
        LocalDate today = LocalDate.now();
        LocalDate monthEnd = today.withDayOfMonth(today.lengthOfMonth());
        return Date.from(monthEnd.atTime(23, 59, 59).atZone(ZoneId.systemDefault()).toInstant());
    }
}
